CloudFormationのDeletion Policyはスタックが削除されるタイミングに限らずリソースが削除されるタイミングでも動作する件
スタックが削除される時でなければDeletionPolicyのRetainは効かない?
こんにちは、のんピ(@non____97)です。
皆さんはスタックが削除される時でなければDeletionPolicyのRetainは効かないのか気になったことはありますか? 私はあります。
AWS公式ドキュメントにはDeletionPolicyは「スタックが削除された際に」という条件しか記載ありません。
DeletionPolicy 属性を使用すると、スタックが削除された際にリソースをRetainし、場合によってはバックアップすることもできます。制御する各リソースに対して DeletionPolicy 属性を指定します。DeletionPolicy 属性が設定されていない場合、AWS CloudFormation ではデフォルトでリソースが削除されます。
リソースの論理IDを変更して更新した場合など、スタックの削除ではなく、スタックの更新によってリソースが削除される場合はDeletionPolicyが効かないのでしょうか。
効くとは思いますが、あまり意識せずに普段触っており、確信が持てなかったので検証してみます。
いきなりまとめ
- CloudFormationのDeletion Policyはスタックが削除されるタイミングに限らず、リソースが削除されるタイミングでも動作する
- スタック更新中にロールバックした場合もDeletionPolicyは効く
やってみた
DeletionPolicyをRetainにしたリソースの作成
では、やってみます。
まず、DeletionPolicyをRetainにしたリソースの作成をします。
使用するテンプレートは以下の通りです。
AWSTemplateFormatVersion: "2010-09-09" Conditions: IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1] Resources: AWSServiceRoleForGlobalAccelerator: Condition: IsControlPlaneRegion DeletionPolicy: Retain Type: "AWS::IAM::ServiceLinkedRole" Properties: AWSServiceName: globalaccelerator.amazonaws.com
AWS CLIでStackを作成します。
$ aws cloudformation deploy \ --stack-name service-linked-role-globalaccelerator \ --template-file service-linked-role.yml \ --capabilities CAPABILITY_NAMED_IAM \ --region us-east-1 Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - service-linked-role-globalaccelerator
作成後、Stackのイベントを確認します。特にエラーなく完了していますね。
リソースも問題なく作成完了しています。
DeletionPolicyをRetainにしたリソースの削除
それでは、DeletionPolicyをRetainにしたリソースの削除をしようとしてみます。
テンプレートを以下のように変更しました。
- 論理IDを
AWSServiceRoleForGlobalAccelerator
からAWSServiceRoleForGlobalAccelerator2
に変更 CustomSuffix
を付与- 既存のAWSServiceRoleForGlobalAcceleratorとロール名が重複したことによるエラーを防ぐ
AWSTemplateFormatVersion: "2010-09-09" Conditions: IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1] Resources: AWSServiceRoleForGlobalAccelerator2: Condition: IsControlPlaneRegion DeletionPolicy: Retain Type: "AWS::IAM::ServiceLinkedRole" Properties: AWSServiceName: globalaccelerator.amazonaws.com CustomSuffix: TestSuffix
それでは変更セットを作成します。
$ aws cloudformation deploy \ --stack-name service-linked-role-globalaccelerator \ --template-file service-linked-role.yml \ --capabilities CAPABILITY_NAMED_IAM \ --region us-east-1 \ --no-execute-changeset Waiting for changeset to be created.. Changeset created successfully. Run the following command to review changes: aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067
作成した変更セットを確認します。
aws cloudformation describe-change-set \ --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067 { "Changes": [ { "Type": "Resource", "ResourceChange": { "Action": "Add", "LogicalResourceId": "AWSServiceRoleForGlobalAccelerator2", "ResourceType": "AWS::IAM::ServiceLinkedRole", "Scope": [], "Details": [] } }, { "Type": "Resource", "ResourceChange": { "Action": "Remove", "LogicalResourceId": "AWSServiceRoleForGlobalAccelerator", "PhysicalResourceId": "AWSServiceRoleForGlobalAccelerator", "ResourceType": "AWS::IAM::ServiceLinkedRole", "Scope": [], "Details": [] } } ], "ChangeSetName": "awscli-cloudformation-package-deploy-1690698779", "ChangeSetId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067", "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/service-linked-role-globalaccelerator/e95ecaa0-2ea1-11ee-88eb-12a6b76090b7", "StackName": "service-linked-role-globalaccelerator", "Description": "Created by AWS CLI at 2023-07-30T06:32:59.614445 UTC", "Parameters": null, "CreationTime": "2023-07-30T06:33:00.949000+00:00", "ExecutionStatus": "AVAILABLE", "Status": "CREATE_COMPLETE", "StatusReason": null, "NotificationARNs": [], "RollbackConfiguration": {}, "Capabilities": [ "CAPABILITY_NAMED_IAM" ], "Tags": null, "ParentChangeSetId": null, "IncludeNestedStacks": false, "RootChangeSetId": null }
論理IDAWSServiceRoleForGlobalAccelerator2
が追加されて、論理IDAWSServiceRoleForGlobalAccelerator
が削除されそうですね。
それでは、こちらの変更セットを実行します。
$ aws cloudformation execute-change-set \ --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067
実行後、Stackのイベントを確認するとResource handler returned message: "Custom suffix is not allowed for globalaccelerator.amazonaws.com
とエラーになっていました。
どうやらAWSServiceRoleForGlobalAccelerator
はカスタムサフィックスを指定できないようです。
しょうがないので、テンプレートを以下のようにAWSServiceRoleForCloudHSM
を作成するようなものに変更します。
AWSTemplateFormatVersion: "2010-09-09" Conditions: IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1] Resources: AWSServiceRoleForCloudHSM: Condition: IsControlPlaneRegion DeletionPolicy: Retain Type: "AWS::IAM::ServiceLinkedRole" Properties: AWSServiceName: cloudhsm.amazonaws.com
それでは変更セットを作成して、作成された変更セットを確認します。
$ aws cloudformation deploy \ --stack-name service-linked-role-globalaccelerator \ --template-file service-linked-role.yml \ --capabilities CAPABILITY_NAMED_IAM \ --region us-east-1 \ --no-execute-changeset Waiting for changeset to be created.. Changeset created successfully. Run the following command to review changes: aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287 $ aws cloudformation describe-change-set \ --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287 { "Changes": [ { "Type": "Resource", "ResourceChange": { "Action": "Add", "LogicalResourceId": "AWSServiceRoleForCloudHSM", "ResourceType": "AWS::IAM::ServiceLinkedRole", "Scope": [], "Details": [] } }, { "Type": "Resource", "ResourceChange": { "Action": "Remove", "LogicalResourceId": "AWSServiceRoleForGlobalAccelerator", "PhysicalResourceId": "AWSServiceRoleForGlobalAccelerator", "ResourceType": "AWS::IAM::ServiceLinkedRole", "Scope": [], "Details": [] } } ], "ChangeSetName": "awscli-cloudformation-package-deploy-1690699228", "ChangeSetId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287", "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/service-linked-role-globalaccelerator/e95ecaa0-2ea1-11ee-88eb-12a6b76090b7", "StackName": "service-linked-role-globalaccelerator", "Description": "Created by AWS CLI at 2023-07-30T06:40:28.682688 UTC", "Parameters": null, "CreationTime": "2023-07-30T06:40:30.020000+00:00", "ExecutionStatus": "AVAILABLE", "Status": "CREATE_COMPLETE", "StatusReason": null, "NotificationARNs": [], "RollbackConfiguration": {}, "Capabilities": [ "CAPABILITY_NAMED_IAM" ], "Tags": null, "ParentChangeSetId": null, "IncludeNestedStacks": false, "RootChangeSetId": null }
論理IDAWSServiceRoleForCloudHSM
が追加されて、論理IDAWSServiceRoleForGlobalAccelerator
が削除されそうですね。
こちらの変更セットを実行します。
$ aws cloudformation execute-change-set \ --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287
実行後のイベントは以下のようになっていました。
問題なく更新できていますね。論理IDAWSServiceRoleForGlobalAccelerator
はDELETE_SKIPPED
となっていることが分かります。
リソースタブからも論理IDAWSServiceRoleForGlobalAccelerator
は無くなっています。
IAMのコンソールからAWSServiceRoleForGlobalAcceleratorが残っているか確認すると、確かに削除されずに存在していました。
スタック更新中にロールバックした場合もDeletionPolicy Retainは効くのか
スタック更新中にロールバックした場合もDeletionPolicy Retainは効くのか気になったので検証してみます。
以下のようにDeletionPolicyがRetainなリソースAWSServiceRoleForGlobalAccelerator
作成後に、必ず作成に失敗するAWSServiceRoleForGlobalAccelerator2
を定義してみました。
AWSTemplateFormatVersion: "2010-09-09" Conditions: IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1] Resources: AWSServiceRoleForGlobalAccelerator: Condition: IsControlPlaneRegion DeletionPolicy: Retain Type: "AWS::IAM::ServiceLinkedRole" Properties: AWSServiceName: globalaccelerator.amazonaws.com AWSServiceRoleForGlobalAccelerator2: Condition: IsControlPlaneRegion DeletionPolicy: Retain DependsOn: AWSServiceRoleForGlobalAccelerator Type: "AWS::IAM::ServiceLinkedRole" Properties: AWSServiceName: globalaccelerator.amazonaws.com CustomSuffix: TestSuffix
IAMのコンソールから先の検証で作成したAWSServiceRoleForGlobalAcceleratorを削除しておきます。
この状態でStackを更新します。
$ aws cloudformation deploy \ --stack-name service-linked-role-globalaccelerator \ --template-file service-linked-role.yml \ --capabilities CAPABILITY_NAMED_IAM \ --region us-east-1 Waiting for changeset to be created.. Waiting for stack create/update to complete Failed to create/update the stack. Run the following command to fetch the list of events leading up to the failure aws cloudformation describe-stack-events --stack-name service-linked-role-globalaccelerator
Stackの更新に失敗していますね。
イベントを確認すると、論理IDAWSServiceRoleForGlobalAccelerator
はDELETE_SKIPPED
となっていることが分かります。また、作成に失敗した論理IDAWSServiceRoleForGlobalAccelerator2
もDELETE_SKIPPED
となっていました。
リソースタブから論理IDAWSServiceRoleForGlobalAccelerator
とAWSServiceRoleForGlobalAccelerator2
のリソースが存在しないことを確認します。
IAMのコンソールからAWSServiceRoleForGlobalAcceleratorが残っているか確認すると、確かに削除されずに存在していました。
そのため、CloudFormationでDeletion PolicyをRetainにしているリソースが含まれている場合に、Stackの作成に失敗するとそのリソースが残ることになります。
もし、そのリソースの物理IDを固定している場合はStackの再作成をする際に「同じ名前のリソースが存在する」とエラーになるでしょう。
Deletion Policyでどのリソースが残るのか意識しよう
CloudFormationのDeletion Policyはスタックが削除されるタイミングに限らず、リソースが削除されるタイミングでも動作することを確認しました。
間違ってリソースが削除されることを防ぐ意味でDeletion Policyは便利ですが、意識しなければ不要なリソースが残り続けたり、Stackの再作成をしようとした時に思わぬところでエラーになりそうです。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!